﻿#include "stdafx.h"
#include "fstart.h"
#include "fstartDlg.h"
#include "afxdialogex.h"
#include "Core.h"
#include <vector>
#include "SuggestListDlg.h"
#include "DBDao.h"

using namespace std;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define DlgWidth 400
#define DlgHeight 80

// CfstartDlg 对话框
CfstartDlg::CfstartDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CfstartDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	trueClose = false;  //默认点击关闭按钮是最小化隐藏
}



//当用户拖动最小化窗口时系统调用此函数取得光标;
//显示。
HCURSOR CfstartDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


	#pragma region - 事件 -

	BEGIN_MESSAGE_MAP(CfstartDlg, CDialogEx)
		ON_WM_PAINT()
		ON_WM_QUERYDRAGICON()
		ON_EN_CHANGE(IDC_Command, &CfstartDlg::OnChangeCommand)
		ON_WM_CLOSE()
		ON_WM_HOTKEY()
		ON_WM_MOVING()
		ON_WM_MOVE()
		ON_EN_SETFOCUS(IDC_Command, &CfstartDlg::OnCommandSetfocus)
//		ON_WM_NCPAINT()
	END_MESSAGE_MAP()

	#pragma region OnInitDialog

	BOOL CfstartDlg::OnInitDialog()
	{
		CDialogEx::OnInitDialog();
		RegisterHotKey(GetSafeHwnd(),WM_HOTKEY,MOD_WIN,'Q');  //注册全局热键
		SetIcon(m_hIcon, TRUE);			// 设置大图标
		SetIcon(m_hIcon, FALSE);		// 设置小图标

		#pragma region - 控件初始化 -

		dlgSuggestList = new CSuggestListDlg(this);
		dlgSuggestList->Create(IDD_SuggestDialog,this);

		tbCommand = (CEdit*)GetDlgItem(IDC_Command);

		#pragma endregion

		tbCommand->SetFocus();

		#pragma region - 设置开机启动 -

		SetAutoRun();

		#pragma endregion

		ModifyStyleEx(WS_EX_APPWINDOW,   WS_EX_TOOLWINDOW);
		if (IsWindowStart())
		{
			WINDOWPLACEMENT wp;
			wp.length = sizeof(WINDOWPLACEMENT);
			wp.showCmd = SW_HIDE;
			SetWindowPlacement(&wp);
		}

		DBDao dao;
		dao.Load();

		//动态设置窗体大小
		SetWindowPos(&wndTopMost,   0,   0,  DlgWidth, DlgHeight,  SWP_SHOWWINDOW | SWP_NOMOVE);  
		CenterWindow();

		return FALSE;   //如果设置了tbcommand焦点，则返回false
	}

	#pragma endregion
	
	#pragma region OnPaint

	void CfstartDlg::OnPaint()
	{
		if (IsIconic())
		{
			CPaintDC dc(this);

			SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

			// 使图标在工作区矩形中居中
			int cxIcon = GetSystemMetrics(SM_CXICON);
			int cyIcon = GetSystemMetrics(SM_CYICON);
			CRect rect;
			GetClientRect(&rect);
			int x = (rect.Width() - cxIcon + 1) / 2;
			int y = (rect.Height() - cyIcon + 1) / 2;

			// 绘制图标
			dc.DrawIcon(x, y, m_hIcon);
		}
		else
		{
			CDialogEx::OnPaint();
		}
	}

	#pragma endregion

	#pragma region OnMoving

	void CfstartDlg::OnMoving(UINT fwSide, LPRECT pRect)
	{
		CDialogEx::OnMoving(fwSide, pRect);

		//隐藏提示框
		if (dlgSuggestList)
		{
			dlgSuggestList->ShowWindow(SW_HIDE);
		}

	}

	#pragma endregion
	
	#pragma region OnChangeCommand

	/************************************************************************
	 说明：文本框变化事件											
	************************************************************************/
	void CfstartDlg::OnChangeCommand()
	{
		if (modifiedByUser)
		{
			ShowSuggestDlg();
		}
	}

	#pragma endregion

	#pragma region PreTranslateMessage

	/************************************************************************
	 说明：消息预处理									
	************************************************************************/
	BOOL CfstartDlg::PreTranslateMessage(MSG* pMsg)
	{
		#pragma region 键盘事件响应

		if(pMsg-> message   ==   WM_KEYDOWN) 
		{ 
			switch (pMsg->wParam)
			{
			case VK_RETURN:
				CommandSubmit();
				return TRUE;

			case VK_ESCAPE:
				theApp.HideApplication();
				return TRUE;

			case VK_DOWN:
				tbCommand->GetWindowText(beforeSuggest);
				dlgSuggestList->HightFirstItem();
				return TRUE;

			case VK_UP:
				tbCommand->GetWindowText(beforeSuggest);
				dlgSuggestList->HightLastItem();
				return TRUE;
			}
		} 

		#pragma endregion

		return CDialog::PreTranslateMessage(pMsg);
	}

	#pragma endregion

	#pragma region OnHotKey

	/************************************************************************
	 说明：
		热键处理事件
	 参数：
	 nHotKeyId
		 IDHOT_SNAPDESKTOP - The snap desktop hot key was pressed.
		 IDHOT_SNAPWINDOW - The snap window hot key was pressed.
	 nKey1
		MOD_ALT - Either ALT key was held down.
		MOD_CONTROL - Either CTRL key was held down.
		MOD_SHIFT - Either SHIFT key was held down.
		MOD_WIN - Either WINDOWS key was held down. These keys are labeled with the Microsoft Windows logo.
	 nKey2
		The virtual key code of the hot key.													
	************************************************************************/
	void CfstartDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
	{
		//开机自启动时候，窗体的状态是显示（虽然看不见界面），所以按热键的时候需要按
		//两次才能显示出来，用一下代码解决此BUG
		if(firstHotKey && IsWindowStart())
		{
			CString hasExistedCommand;
			tbCommand->GetWindowText(hasExistedCommand);
			tbCommand->SetFocus();
			tbCommand->SetSel(0,hasExistedCommand.GetLength()); //全选
			SetWindowPos(&wndTopMost,   0,   0,  400, 80,  SWP_SHOWWINDOW | SWP_NOMOVE); 
			CenterWindow();

			firstHotKey = false;
			return;
		}

		if(IsWindowVisible())
		{
			theApp.HideApplication();
		}
		else
		{
			CString hasExistedCommand;
			tbCommand->GetWindowText(hasExistedCommand);
			tbCommand->SetFocus();
			tbCommand->SetSel(0,hasExistedCommand.GetLength()); //全选
			//ModifyStyleEx(WS_EX_TOOLWINDOW,   WS_EX_APPWINDOW);
			SetWindowPos(&wndTopMost,   0,   0,  DlgWidth, DlgHeight,  SWP_SHOWWINDOW | SWP_NOMOVE);  
			CenterWindow();
		}

		CDialogEx::OnHotKey(nHotKeyId, nKey1, nKey2);
	}

	#pragma endregion

	#pragma region OnClose

	void CfstartDlg::OnClose()
	{
		if(trueClose)
		{
			UnregisterHotKey(GetSafeHwnd(),WM_HOTKEY);  
			CDialogEx::OnClose();
		}
		else
		{
			theApp.HideApplication();
		}
	}

	#pragma endregion

	#pragma region OnCommandSetfocus

	void CfstartDlg::OnCommandSetfocus()
	{
		modifiedByUser = true;
	}

	#pragma endregion

	#pragma endregion

	#pragma region - 方法 -
	
	void CfstartDlg::ShowSuggestDlg()
	{
		SetSuggestDlgPosition();

		CString command;
		GetDlgItemText(IDC_Command,command);
		if(command == "")
		{
			//MessageBox(_T("请填写关键字"));
			return;
		}

		Core c;
		vector<CommandModel> files = c.FindAllPossibleCommand(command);

		CListCtrl* listControl=(CListCtrl*)dlgSuggestList->GetDlgItem(IDC_ListControl); 
		
		listControl->DeleteAllItems();
		for (int i = 0;i<files.size();i++)
		{
			CString name = files[i].GetCommand();
			CString path = files[i].GetCommandPath();
			listControl->InsertItem(i,name);
		}

		//将第一项填充到输入框并全选

	}



	/************************************************************************
	 说明：
		设置建议下拉框的位置以及大小，并显示出来
	 ************************************************************************/
	void CfstartDlg::SetSuggestDlgPosition()
	{
		CRect rc;
		GetDlgItem(IDC_Command)->GetWindowRect(&rc);  //获得命令输入框的位置信息（相对于屏幕）
		dlgSuggestList->SetWindowPos(&wndTopMost,rc.left,rc.bottom,rc.right-rc.left,200/*提示下拉框高度*/,SWP_SHOWWINDOW);  
		dlgSuggestList->ShowWindow(SW_SHOW);

		dlgSuggestList->lcSuggest->SetWindowPos(&wndTop,0,0,rc.right-rc.left,200,SWP_SHOWWINDOW);

		//将焦点移动到命令输入框
		tbCommand->SetFocus();
	}

	void CfstartDlg::SetAutoRun()
	{
		CString startPath = utility.GetCurExePath()+" min";
		utility.SetAutoRun(_T("fstart"),startPath);
	}

	/************************************************************************
	 说明：
		处理内置命令
	　参数：
		命令
	　返回值：
		处理成功返回true，失败返回false
	 ************************************************************************/
	bool CfstartDlg::ProcessCommandInside( CString command )
	{
		if (command == "exit")
		{
			trueClose = true;
			SendMessage(WM_CLOSE);
			return true;
		}

		return false;
	}

	void CfstartDlg::CommandSubmit()
	{
		CString command;
		tbCommand->GetWindowText(command);

		if(!ProcessCommandInside(command))
		{
			//不是内置命令则继续处理
			DBDao dao;
			Core core;
			vector<CommandModel> resList = core.FindAllPossibleCommand(command);
			if(resList.size() > 0)
			{
				if(utility.Execute(resList[0].GetCommandPath()))
				{
					this->ShowWindow(SW_HIDE);
					dlgSuggestList->ShowWindow(SW_HIDE);
					
					//将执行成功的命令加入历史记录
					dao.InsertOrUpdateCommand(resList[0].GetCommand(),resList[0].GetCommandPath());
					dao.Save();
				}
				else
				{
					AfxMessageBox(_T("执行失败"));
				}
			}
		}
	}

	/************************************************************************
	 说明：
		判断程序是否是开机自启动的
	 ************************************************************************/
	bool CfstartDlg::IsWindowStart()
	{
		 int argvCount;
		 LPWSTR *argvs = CommandLineToArgvW(GetCommandLine(),&argvCount);
		 
		 if (argvCount > 1)
		 {
			 CString argv = argvs[1];
			 if (argv == "min")
			 { 
				 return true;
			 }
		 }

		 return false;
	}

	#pragma endregion
